{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 第2章 用C++设计一些常见的低延迟应用"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "> 那个天天给我发通知消息而不含广告内容的10086客服姑娘，我们终于在一起了。\n",
    "\n",
    "在本章中，我们将研究视频流、在线游戏、实时数据分析和电子交易等不同领域的一些应用。我们将了解它们的行为，以及在极低延迟的考量下哪些功能需要实时执行。我们还将介绍电子交易生态系统，因为在本书的其余部分，我们将以此为案例研究，用C++从头开始构建一个系统，重点是理解和运用低延迟理念。\n",
    "\n",
    "在本章中，我们将涵盖以下主题：\n",
    "\n",
    "- 理解直播视频流应用中的低延迟性能\n",
    "- 了解在游戏应用中哪些低延迟约束很重要\n",
    "- 讨论物联网（Internet-of-Things，IoT）和零售分析系统的设计\n",
    "- 探索低延迟电子交易\n",
    "\n",
    "本章的目标是深入探讨不同业务领域中低延迟应用的一些技术方面。在本章结束时，你应该能够理解和认识到实时视频流、离线和在线游戏应用、物联网设备和应用以及电子交易等应用所面临的技术挑战。你将能够了解技术进步所提供的不同解决方案，以解决这些问题，并使这些业务可行且有利可图。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# 探索低延迟电子交易/Exploring low latency electronic trading"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "低延迟应用的最后一个例子是用于低延迟电子交易和超低延迟电子交易（也称为高频交易，HFT）的应用。在本书的后续部分，我们将用C++从头开始构建一个完整的端到端低延迟电子交易系统。因此，在本节中，我们将简要讨论电子交易应用实现低延迟性能的重要注意事项，然后在后续章节中深入探讨具体细节。对于有兴趣的读者来说，Sebastian Donadio、Sourav Ghosh和Romain Rossier所著的《Developing High-Frequency Trading Systems》是一本深入了解低延迟电子交易系统的优秀书籍。本书的重点是用C++从头开始设计和构建每个组件，以学习低延迟应用开发，而那本书可以作为高频交易业务背后更多理论的良好参考。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 理解现代电子交易中对低延迟的需求\n",
    "\n",
    "随着电子交易的现代化和高频交易的兴起，低延迟对于这些应用比以往任何时候都更加重要。在许多情况下，降低延迟能直接增加交易收入。在某些情况下，市场参与者不断竞相降低延迟，以在市场中保持竞争优势。在极端情况下，如果参与者在追求尽可能低延迟的竞争中落后，可能会面临倒闭。\n",
    "\n",
    "现代电子市场中的交易机会转瞬即逝，因此只有那些能够处理市场数据、发现机会并迅速做出反应发送订单的市场参与者才能盈利。反应不够迅速意味着只能抓住较小的机会份额，通常只有最快的参与者才能获得全部利润，而其他速度较慢的参与者则一无所获。这里还有一个微妙之处，如果参与者对市场事件反应不够迅速，还可能在交易中处于不利地位，输给那些能够快速反应的人。在这种情况下，交易利润不仅会降低，交易收入甚至可能为负（即亏损）。为了更好地理解这一点，让我们以本书中会构建的做市和流动性获取算法为例进行说明。\n",
    "\n",
    "简单来说，做市算法会在市场中下达订单，其他参与者在需要时可以与之交易。因此，做市算法需要不断重新评估其活跃订单，并根据市场情况调整价格和数量。而流动性获取算法并不总是在市场中有活跃订单，它会等待机会出现，然后与市场中做市算法的活跃订单进行交易。高频交易市场可以简单地看作是做市算法和流动性获取算法之间的持续博弈，因为它们自然处于对立的立场。\n",
    "\n",
    "在这种情况下，做市算法如果在修改市场中的活跃订单时速度较慢就会赔钱。例如，根据市场情况很明显短期内市场价格会上涨，做市算法会试图调整或取消其可能被执行的卖出订单，因为它不再想以这些价格卖出。与此同时，流动性获取算法会尝试查看是否可以发送买入订单，以该价格与做市商的卖出订单进行交易。在这场竞争中，如果做市算法比流动性获取算法慢，它将无法修改或取消其卖出订单。如果流动性获取算法速度慢，它也无法与它想要交易的订单成交，这可能是因为其他（更快的）算法抢先成交，或者是做市商及时调整了订单。这个例子应该能让你清楚地认识到，延迟直接影响电子交易的收入。\n",
    "\n",
    "对于高频交易，客户端的交易应用程序可以在10微秒以内的延迟内接收和处理市场数据、分析信息、寻找机会并向交易所发送订单，并且使用现场可编程门阵列（Field - Programmable Gate Arrays，FPGA）可以将延迟降低到1微秒以内。FPGA是一种特殊的硬件芯片，可以重新编程，能够直接在芯片上构建极其专业的低延迟功能。理解FPGA的细节以及开发和使用FPGA是一个高级话题，超出了本书的范围。\n",
    "\n",
    "虽然我们在前面的例子中提到了交易性能和收入，但低延迟在电子交易业务的其他方面也很重要，只是可能不那么明显。显然，交易收入和性能仍然是交易应用的主要关注点；对于长期业务连续性来说，另一个重要要求是实时风险管理。由于每个电子市场都有许多交易工具，并且每个工具的价格在一天中不断变化，风险管理系统需要处理来自所有交易所和全天所有可用产品的大量数据。\n",
    "\n",
    "此外，由于公司在所有这些产品和交易所采用高频交易策略，公司在每个产品上的头寸在一天内会迅速变化。实时风险管理系统需要根据市场价格评估公司在所有这些产品上不断变化的风险敞口，以跟踪全天的利润、损失和风险。风险评估指标和系统本身可能非常复杂；例如，在期权交易中，通常会运行蒙特卡罗模拟，试图实时或接近实时地找出最坏情况下的风险评估。一些风险管理系统还负责在自动交易策略超出任何风险限制时将其关闭。这些风险系统通常会添加到多个组件中——中央风险系统、订单网关和交易策略本身——但我们将在本书后面的内容中了解这些细节。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 在电子交易中实现最低延迟"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "在本节中，我们将简要讨论实现低延迟电子交易系统的一些高层次的思路和概念。当然，在接下来的章节中构建电子交易生态系统时，我们会通过示例更详细地探讨这些内容。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 优化交易服务器硬件\n",
    "\n",
    "配备强大的交易服务器以支持低延迟交易操作是第一步。通常，这些服务器的处理能力取决于交易系统进程的架构，比如我们预期运行多少个进程、预计消耗多少网络资源，以及这些应用程序预计占用多少内存。一般来说，在交易繁忙时期，低延迟交易应用程序具有CPU使用率高、内核使用率（系统调用）低、内存消耗低，以及网络资源使用率相对较高的特点。CPU寄存器、缓存架构和容量也很重要，通常情况下，如果可能的话，我们会尽量选择更大的规格，不过这些成本可能相当高。像非统一内存访问（Non-Uniform Memory Access，NUMA）、处理器指令集、指令流水线和指令并行性、缓存层次结构详细架构、超线程技术，以及超频CPU等高级因素，虽然常常会被考虑，但这些都属于极其高级的优化技术，超出了本书的讨论范围。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 网络接口卡、交换机和内核旁路\n",
    "\n",
    "需要支持超低延迟交易应用程序（尤其是那些必须读取大量市场数据、更新网络数据包并进行处理的应用程序）的交易服务器，需要专门的网络接口卡（Network Interface Cards，NICs）和交换机。这类应用程序偏好的网络接口卡需要具备极低的延迟性能、低抖动，以及大缓冲区容量，以便在处理市场数据突发情况时不会丢包。此外，适用于现代电子交易应用程序的理想网络接口卡支持一种特别低延迟的路径，能够避免系统调用和缓冲区复制，这被称为内核旁路（kernel bypass）。例如Solarflare公司提供的OpenOnload以及像ef_vi和TCPDirect这样的API，在使用其网络接口卡时可以绕过内核；Exablaze则是另一种支持内核旁路的专用网络接口卡。网络交换机出现在网络拓扑的各个位置，用于支持交易服务器之间、相距较远的交易服务器之间，以及交易服务器与电子交易所服务器之间的互联互通。对于网络交换机，一个重要的考虑因素是交换机能够支持的缓冲区大小，以便缓存需要转发的数据包。另一个重要要求是交换机接收数据包并将其转发到正确接口之间的延迟，即交换延迟（switching latency）。交换延迟通常非常低，一般在几百纳秒的量级，但这适用于通过交换机的所有入站或出站流量，所以需要始终保持低延迟，以免对交易性能产生负面影响。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 理解多线程、锁、上下文切换和CPU调度\n",
    "\n",
    "在上一章中，我们讨论了带宽和低延迟这两个密切相关但在技术层面有所不同的概念。有时人们会错误地认为，线程数量更多的架构总是具有更低的延迟，但事实并非总是如此。多线程在低延迟电子交易系统的某些领域有其价值，在本书构建的系统中我们也会用到它。但关键在于，在**高频交易（HFT，High-Frequency Trading ）系统**中使用额外线程时需要谨慎，因为虽然增加线程通常能为有需求的应用程序提高吞吐量，但有时也可能会增加应用程序的延迟。随着线程数量的增加，我们必须考虑并发和线程安全问题，如果需要使用锁来实现线程之间的同步和并发控制，这会增加额外的延迟和上下文切换（context switches）开销。上下文切换并非没有成本，因为调度器和操作系统必须保存被切换出的线程或进程的状态，并加载下一个要运行的线程或进程的状态。许多锁的实现是基于内核系统调用，这比用户空间例程的成本更高，从而进一步增加了高度多线程应用程序的延迟。为了实现最佳性能，我们尽量让CPU调度器少做甚至不做工作（即被调度运行的进程和线程永远不会被上下文切换出去，而是持续在用户空间中运行）。此外，将特定的线程和进程固定到特定的CPU核心上是很常见的做法，这可以消除上下文切换，也无需操作系统寻找空闲核心来调度任务，进而提高内存访问效率。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 动态分配内存和管理内存\n",
    "\n",
    "动态内存分配（Dynamic memory allocation）是在运行时请求任意大小的内存块。从高层次来看，动态内存的分配和释放由操作系统负责，操作系统会遍历一个空闲内存块列表，尝试分配一个与程序请求大小相同的连续内存块。动态内存的释放则是将释放的内存块添加到操作系统管理的空闲块列表中。随着程序的运行，内存碎片化程度越来越高，遍历这个列表所带来的延迟也会越来越高。此外，如果动态内存的分配和释放在同一关键路径上，那么每次都会产生额外的开销。这就是我们之前讨论过的选择C++作为构建低延迟和资源受限应用程序首选语言的主要原因之一。在本书后面构建自己的交易系统时，我们将探讨动态内存分配对性能的影响，以及避免这种影响的技术。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "#### 静态链接与动态链接，编译时与运行时\n",
    "\n",
    "链接（Linking）是将高级编程语言源代码转换为目标架构机器码过程中的编译或转换步骤。链接将可能位于不同库中的代码片段连接在一起，这些库可以是代码库内部的库，也可以是外部独立库。在链接步骤中，我们有两种选择：静态链接（Static linking）或动态链接（Dynamic linking）。 动态链接是指链接器在链接时不会将库中的代码合并到最终的二进制文件中。相反，当主应用程序首次需要共享库中的代码时，会在运行时进行解析。显然，在首次调用共享库代码时，运行时会产生特别大的额外开销。更大的缺点是，由于编译器和链接器在编译和链接时没有将代码合并进去，它们无法进行可能的优化，从而导致整个应用程序的效率可能较低。 **静态链接**是指链接器将应用程序代码和库依赖代码整理到一个二进制可执行文件中。这样做的好处是库在编译时已经链接好，因此在应用程序启动执行之前，操作系统无需在运行时启动阶段查找并解析依赖关系，加载相关库。更大的好处是，这为程序在编译和链接时进行深度优化创造了机会，从而在运行时实现更低的延迟。与动态链接相比，静态链接的缺点是应用程序二进制文件会大得多，而且每个依赖相同外部库集的应用程序二进制文件，都会将所有外部库代码编译并链接到自身二进制文件中。为了最大程度降低运行时的性能延迟，超低延迟电子交易系统通常会静态链接所有依赖库。 在上一章中，我们讨论了编译时与运行时处理，这种方式试图将尽可能多的处理工作转移到编译阶段，而不是在运行时进行。这会增加编译时间，但运行时的性能延迟会低得多，因为很多工作在编译时已经完成。在接下来的几章以及本书构建C++电子交易系统的过程中，我们将详细探讨C++在这方面的具体情况。"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "## 总结\n",
    "\n",
    "在本章中，我们研究了不同业务领域的低延迟应用程序。目的是了解低延迟应用程序如何影响不同领域的业务，以及这些应用程序的一些共同之处，比如硬件需求和优化、软件设计、性能优化，以及为满足这些性能要求所采用的不同创新技术。\n",
    "\n",
    "我们首先详细研究的是实时、低延迟的在线视频流应用程序。我们讨论了不同的概念，探究了高延迟的来源，以及它对性能和业务的影响。最后，我们讨论了不同的技术、解决方案和平台，这些因素共同助力低延迟视频流应用程序取得成功。\n",
    "\n",
    "接下来我们研究的应用程序与视频流应用程序有很多重叠之处，即离线和在线视频游戏应用程序。我们介绍了一些适用于离线和在线游戏应用程序的额外概念和注意事项，并解释了它们对用户体验的影响，进而对业务表现的影响。我们讨论了在试图最大化这些应用程序性能时需要考虑的众多因素，涵盖了许多与直播视频流应用程序相关的因素，以及针对游戏应用程序的额外硬件和软件方面的考虑。 然后，我们简要讨论了物联网设备以及零售数据收集和分析应用程序对低延迟性能的要求。这是一项相对较新且发展迅速的技术，在未来十年可能会继续迅猛发展。目前在物联网设备方面有很多研究和进展，随着研究的深入，我们也发现了新的商业理念和应用案例。我们讨论了5G无线和边缘计算技术如何打破传统的集中式数据存储和处理模式，以及这对物联网设备和应用程序为何至关重要。 本章最后我们还简要讨论了低延迟电子交易和高频交易应用程序。我们的讨论较为简短，重点关注了最大化低延迟和超低延迟电子交易应用程序性能的高层次理念。之所以这样做，是因为在本书的后续章节中，我们将从头开始构建一个完整的端到端C++低延迟电子交易生态系统。在构建过程中，我们将通过示例和性能数据，深入讨论、理解并实现所有不同的低延迟C++概念和理念，所以关于这个应用程序还有很多内容值得期待。\n",
    "\n",
    "从对不同低延迟应用程序的讨论出发，接下来我们将更深入地探讨C++编程语言。我们将讨论如何正确使用C++实现低延迟性能，探讨现代C++的不同特性，以及如何充分发挥现代C++编译器优化的强大功能。"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "C++17",
   "language": "C++17",
   "name": "xcpp17"
  },
  "language_info": {
   "name": "C++17"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
